/*
功能说明:
1 提供内存极缓冲区给业务线程存储日志消息-string,不直接输出到文件中，先输出到缓冲区中
2 当缓冲区满了的时候通知日志线程来拿数据进行日志落地输出
好处：业务线程只需将日志消息放入到缓冲区交给其它线程处理即可，不会因为输出日志而阻塞业务线程

实现：生产者（业务线程）-消费者（日志线程）模型
临界资源--缓冲区，对临界资源加锁

缓冲区设计：采用双缓冲区设计，生产者生产日志放入缓冲区1，消费者从缓冲区2拿数据
缓冲区1数据放入一定数量时，把指向两个缓冲区的指针交换一下即可
好处：减少了生产者和消费者锁的冲突
生产者只需给缓冲区1加锁即可，消费者给缓冲区2加锁即可
*/
#pragma once
#include <iostream>
#include <vector>
#include <string>
namespace MyLogBuffer
{
#define MaxBSize (1024 * 1024) // 缓冲区固定大小，不让扩容，资源有限
    class LogBuffer
    {
    public:
        LogBuffer() : _buffer(MaxBSize), _MaxBsize(MaxBSize), _rindex(0), _windex(0) // 提前开好空间
        {}
        // 缓冲区写入数据
        void push(const std::string &logmessage)
        {
            // 如果缓冲区已经满了那么阻塞
            if (_windex >= _MaxBsize)
            {
                std::cerr << "buffer is full" << std::endl;
                return;
            }
            _buffer[_windex++] = logmessage;
        }
        // 返回当前读位置的日志
        const std::string &GetCurRPos()
        {
            return _buffer[_rindex];
        }
        // 读位置向后偏移
        void ReadPosOffSet()
        {
            if (_rindex < _windex)
                _rindex++;
        }
        // 返回可读的日志信息个数
        size_t GetRMesNum()
        {
            return _windex - _rindex;
        }
        // 重置读写位置
        void Reset()
        {
            _rindex = _windex = 0;
        }
        // 判断缓冲区是否有有空间
        bool IsWrite()
        {
            return _windex < _MaxBsize;
        }
        bool IsRead() // 判断缓冲区是否有数据
        {
            return _rindex < _windex;
        }
        // 交换缓冲区数据
        void Swap(LogBuffer &buffer)
        {
            _buffer.swap(buffer._buffer);
            // 交换两个缓冲区的读写位置，拷贝
            std::swap(_rindex, buffer._rindex);
            std::swap(_windex, buffer._windex);
        }
    private:
        std::vector<std::string> _buffer; // 存储一条条的字符串日志
        size_t _rindex;                   // 当前读缓冲区的起始位置
        size_t _windex;                   // 当前写缓冲区的起始位置
        size_t _MaxBsize;
    };

};